package conMgr.ui.papers;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import conMgr.model.Conference;
import conMgr.model.Paper;
import conMgr.model.Review;
import conMgr.model.Status;
import conMgr.model.User;
import conMgr.model.UserType;
import conMgr.prog.Program;
import conMgr.ui.bases.JDialogEx;
import conMgr.ui.util.ButtonBar;
import conMgr.ui.util.Ui;

/**
 * Provides a view of a new or existing paper.
 * @author is4@uw.edu
 */
public class PaperView extends JDialogEx
{
	/**
	 * The serialization ID for this class.
	 */
	private static final long serialVersionUID = -6566271237895600993L;

	/**
	 * The assign reviewers view.
	 */
	private final AssignReviewersView assignReviewersView;
	
	/**
	 * The assign subprogram chair view.
	 */
	private final AssignSubprogramChairView assignSubprogramChairView;
	
	/**
	 * The button bar for this panel.
	 */
	private final ButtonBar buttonBar;
	
	/**
	 * The paper info view for this panel.
	 */
	private final PaperInfoView infoView; 
	
	/**
	 * The paper this view will display. This may be null if the paper is new.
	 */
	private final Paper paper;
	
	/**
	 * The recommendation view for this panel.
	 */
	private final RecommendationView recommendationView;
	
	/**
	 * The review view for the current reviewer, or null if none.
	 */
	private ReviewView reviewView = null;
	
	/**
	 * Initializes a new paper object. Callers should pass either a non-null
	 * paper or a non-null conference, but not both.
	 * @param paper The paper to edit or null.
	 * @param conference The conference to submit a new paper to or null.
	 */
	public PaperView(final Paper paper, final Conference conference)
	{
		this.paper = paper;
		
		if (paper == null)
			setTitle("Upload New Paper");
		else
			setTitle("Paper: " + paper.getTitle());
		
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.insets = Ui.DEFAULT_INSETS;
		constraints.gridx = 0;
		constraints.gridy = 0;
		constraints.anchor = GridBagConstraints.NORTHWEST;
		infoView = new PaperInfoView(paper, conference);
		add(infoView, constraints);
		
		constraints = new GridBagConstraints();
		constraints.insets = Ui.DEFAULT_INSETS;
		constraints.gridx = 1;
		constraints.gridy = 0;
		constraints.anchor = GridBagConstraints.NORTHWEST;
		final GridBagLayout layout = new GridBagLayout();
		final JPanel rightPanel = new JPanel(layout);
		final JScrollPane pane = new JScrollPane(rightPanel);
		pane.setBorder(null);
		pane.setPreferredSize(new Dimension(520, 338));
		add(pane, constraints);
		
		constraints = new GridBagConstraints();
		constraints.insets = Ui.DEFAULT_INSETS;
		constraints.gridx = 0;
		constraints.gridwidth = 2;
		constraints.gridy = 1;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		buttonBar = new ButtonBar();
		if
		(
			paper != null &&
			paper.getConference().getProgramChair() == User.getCurrentUser() &&
			paper.getStatus() == Status.RECOMMENDED
		)
		{
			buttonBar.addButton("Accept", new StatusAction(Status.ACCEPTED));
			buttonBar.addButton("Rejected", new StatusAction(Status.REJECTED));
		}
		else
			buttonBar.addButton("Submit", new OkAction());
		buttonBar.addButton("Cancel", new CancelAction());
		add(buttonBar, constraints);
		
		int row = 0;
		if
		(
			paper != null &&
			paper.getConference().getProgramChair() == User.getCurrentUser() &&
			paper.getStatus() == Status.UNDECIDED
		)
		{
			constraints = new GridBagConstraints();
			constraints.insets = Ui.DEFAULT_INSETS;
			constraints.gridx = 0;
			constraints.gridy = row++;
			constraints.fill = GridBagConstraints.HORIZONTAL;
			assignSubprogramChairView = new AssignSubprogramChairView(paper);
			rightPanel.add(assignSubprogramChairView, constraints);
		}
		else
			assignSubprogramChairView = null;
		
		if (paper != null && paper.getSubprogramChair() == User.getCurrentUser())
		{
			constraints = new GridBagConstraints();
			constraints.insets = Ui.DEFAULT_INSETS;
			constraints.gridx = 0;
			constraints.gridy = row++;
			constraints.fill = GridBagConstraints.HORIZONTAL;
			assignReviewersView = new AssignReviewersView(paper);
			rightPanel.add(assignReviewersView, constraints);
		}
		else
			assignReviewersView = null;
		
		if (paper != null)
			for (Review review : paper.getPaperReviews())
				if (shouldSeeReview(review))
				{
					constraints = new GridBagConstraints();
					constraints.insets = Ui.DEFAULT_INSETS;
					constraints.gridx = 0;
					constraints.gridy = row++;
					constraints.fill = GridBagConstraints.HORIZONTAL;
					ReviewView view = new ReviewView(review);
					if (review.getReviewer() == User.getCurrentUser())
						reviewView = view;
					rightPanel.add(view, constraints);
				}
		
		if
		(
			paper != null &&
			paper.getSubprogramChair() != null &&
			(
				paper.getSubprogramChair() == User.getCurrentUser() ||
				paper.getConference().getProgramChair() == User.getCurrentUser() ||
				User.getCurrentUser().getType() == UserType.ADMIN
			)
		)
		{
			constraints = new GridBagConstraints();
			constraints.insets = Ui.DEFAULT_INSETS;
			constraints.gridx = 0;
			constraints.gridy = row++;
			constraints.fill = GridBagConstraints.HORIZONTAL;
			recommendationView = new RecommendationView(paper);
			rightPanel.add(recommendationView, constraints);
		}
		else
			recommendationView = null;
		
		finishSetup();
	}
	
	/**
	 * Determines if the current user should see the given review.
	 * @param review The review to test. 
	 * @return True if the review should be shown; otherwise, false.
	 */
	private boolean shouldSeeReview(final Review review)
	{
		if (paper.getAuthor() == User.getCurrentUser())
			return
				paper.getStatus() == Status.ACCEPTED ||
				paper.getStatus() == Status.REJECTED;
		else if (review.getReviewer() == User.getCurrentUser())
			return true;
		else if (paper.getSubprogramChair() == User.getCurrentUser())
			return true;
		else if (paper.getConference().getProgramChair() == User.getCurrentUser())
			return true;
		else if (User.getCurrentUser().getType() == UserType.ADMIN)
			return true;
		else
			return false;
	}

	/**
	 * Provides an action for the OK button. 
	 */
	class OkAction extends AbstractAction
	{
		/**
		 * The serialization ID of this class.
		 */
		private static final long serialVersionUID = 1341664181816147314L;

		/**
		 * Handles the action. Creates or updates the given paper and closes the
		 * window.
		 */
		@Override
		public void actionPerformed(final ActionEvent arg0)
		{
			if (paper == null)
			{
				final Paper paper = infoView.createPaper();
				
				if (paper == null)
					return;
			}
			else if (assignSubprogramChairView != null)
				assignSubprogramChairView.save();
			else if (assignReviewersView != null)
				assignReviewersView.save();
			else if (reviewView != null)
			{
				final boolean result = reviewView.save();
				
				if (!result)
					return;
			}
			
			if (recommendationView != null)
			{
				final boolean result = recommendationView.save();
				
				if (!result)
					return;
			}
			
			Program.getDataStore().saveAll();
			PaperView.this.close();
		}
	}
	
	/**
	 * Provides an action for the Cancel button.
	 */
	class CancelAction extends AbstractAction
	{
		/**
		 * The serialization ID of this class.
		 */
		private static final long serialVersionUID = 2235460547541514775L;

		/**
		 * Handles the action. Closes the window.
		 */
		@Override
		public void actionPerformed(final ActionEvent arg0)
		{
			PaperView.this.close();
		}
	}
	
	/**
	 * Provides an action to setting the status of the current paper.
	 * @author is4@uw.edu
	 */
	class StatusAction extends AbstractAction
	{
		/**
		 * The serialization ID of this class.
		 */
		private static final long serialVersionUID = 4474056488941700819L;

		/**
		 * The status this action will set.
		 */
		private final Status status;
		
		/**
		 * Initializes a new status action.
		 * @param status The status this action will set.
		 */
		public StatusAction(final Status status)
		{
			this.status = status;
		}
		
		/**
		 * Handles the action. Sets the paper status and closes the window.
		 */
		@Override
		public void actionPerformed(ActionEvent arg0)
		{
			if (status == Status.ACCEPTED)
				PaperView.this.paper.accept();
			else if (status == Status.REJECTED)
				PaperView.this.paper.reject();
			
			PaperView.this.close();
		}
	}
}
